package com.zut.chat.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zut.chat.dto.WebSocketMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocket聊天服务
 */
@Slf4j
@Service
public class ChatWebSocketService {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private UserService userService;

    // 存储所有WebSocket会话
    private final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
    
    // 在线用户计数器（保留作为备用，主要使用数据库统计）
    private final AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 添加WebSocket会话
     */
    public void addSession(String sessionId, WebSocketSession session) {
        sessions.put(sessionId, session);
        int count = onlineCount.incrementAndGet();
        log.info("用户连接: {}, 当前在线人数: {}", sessionId, count);
    }

    /**
     * 移除WebSocket会话
     */
    public void removeSession(String sessionId) {
        WebSocketSession removedSession = sessions.remove(sessionId);
        if (removedSession != null) {
            int count = onlineCount.decrementAndGet();
            log.info("用户断开: {}, 当前在线人数: {}", sessionId, count);
            
            // 立即广播更新后的在线人数给所有连接的客户端
            broadcastOnlineCountUpdate();
        }
    }

    /**
     * 广播在线人数更新
     */
    public void broadcastOnlineCountUpdate() {
        int currentCount = getOnlineCount();
        WebSocketMessage countUpdateMessage = WebSocketMessage.builder()
                .type(WebSocketMessage.MessageType.ONLINE_COUNT)
                .content("在线人数更新")
                .timestamp(java.time.LocalDateTime.now())
                .onlineCount(currentCount)
                .build();
        
        broadcastMessage(countUpdateMessage);
    }

    /**
     * 获取在线用户数（优先使用数据库统计，确保准确性）
     */
    public int getOnlineCount() {
        try {
            // 从数据库获取准确的在线人数
            long dbCount = userService.getOnlineUserCount();
            // 同步内存计数器
            onlineCount.set((int) dbCount);
            return (int) dbCount;
        } catch (Exception e) {
            log.warn("获取数据库在线人数失败，使用内存计数: {}", e.getMessage());
            return onlineCount.get();
        }
    }

    /**
     * 获取实际连接的会话数量
     */
    public int getActiveSessionCount() {
        return sessions.size();
    }

    /**
     * 向所有客户端广播消息
     */
    public void broadcastMessage(WebSocketMessage message) {
        String jsonMessage;
        try {
            jsonMessage = objectMapper.writeValueAsString(message);
        } catch (Exception e) {
            log.error("序列化消息失败", e);
            return;
        }

        sessions.forEach((sessionId, session) -> {
            if (session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(jsonMessage));
                } catch (IOException e) {
                    log.error("发送消息到客户端失败: {}", sessionId, e);
                    // 移除无效会话
                    sessions.remove(sessionId);
                    onlineCount.decrementAndGet();
                }
            } else {
                // 移除已关闭的会话
                sessions.remove(sessionId);
                onlineCount.decrementAndGet();
            }
        });
    }

    /**
     * 向特定客户端发送消息
     */
    public void sendMessageToUser(String sessionId, WebSocketMessage message) {
        WebSocketSession session = sessions.get(sessionId);
        if (session != null && session.isOpen()) {
            try {
                String jsonMessage = objectMapper.writeValueAsString(message);
                session.sendMessage(new TextMessage(jsonMessage));
            } catch (Exception e) {
                log.error("发送消息到用户失败: {}", sessionId, e);
            }
        }
    }

    /**
     * 检查会话是否存在
     */
    public boolean hasSession(String sessionId) {
        return sessions.containsKey(sessionId);
    }
}
